<!--
 * @FilePath: PyramidChart.vue
 * @Author: jack
 * @Date: 2024-06-06 16:29:02
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2024-07-18 09:17:48
 * Copyright: 2024 xxxTech CO.,LTD. All Rights Reserved.
 * @Descripttion: 
-->
<template>
    <div class="PyramidChart">
        <div id="container" :style="{ height: 176 * (data.length / 6) + 'px' }" ref="pyramidChartRef"></div>
    </div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts';
import { ref, onMounted, reactive, watch, nextTick } from 'vue'
import $util from '../../util/util'
interface PropsType {
    chartData?: any
}
const props = withDefaults(defineProps<PropsType>(), {
    chartData: [],
})
const emit = defineEmits<EmitType>()
interface EmitType { }
let myChart: any = null
const clientWidth = ref<number>(document.documentElement.clientWidth)
const pyramidChartRef = ref<any>(null)
const colors = ref<any>([])
let data: any = []
const getCharts = () => {
    if (data.length == 0) return;
    myChart = echarts.init(pyramidChartRef.value);
    // 将数据根据从小到大排序
    // let newdata = sortObject(data);
    // 图例数据
    let lengthData: any = [];
    // 返回数据
    let resultData: any = data.map((item: any, index: number) => {
        lengthData.push({
            type: 'group',
            top: index * 25,
            scale: [1, 1],
            children: [
                {
                    type: 'rect',
                    // left: 'center',
                    // top: 'center',
                    shape: {
                        width: $util.fontSize(9),
                        height: $util.fontSize(9)
                    },
                    style: {
                        icon: "rect",
                        fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                            { offset: 0, color: $util.getNewColorWithTransparency(item.color,0.8,'rgba') },
                            { offset: 1, color: item.color }
                        ]),
                        x: 0,
                        y: 2
                    }
                },
                {
                    type: 'text',
                    style: {
                        text: item.name,
                        fill: '#ffffff',
                        fontSize: $util.fontSize(11),
                        x: $util.fontSize(18),
                        y: 0
                    }
                },
                {
                    type: 'text',
                    name: item.name,
                    style: {
                        text: item.value + '人',
                        fill: '#ffffff',
                        fontWeight: "bold",
                        fontFamily: 'HarmonyOS Sans SC',
                        fontSize: $util.fontSize(11),
                        x: $util.fontSize(85),
                        y: 0
                    }
                },
                {
                    type: 'text',
                    name: item.percentage,
                    style: {
                        text: item.percentage + '%',
                        fill: '#fff',
                        fontWeight: "bold",
                        fontFamily: 'HarmonyOS Sans SC',
                        fontSize: $util.fontSize(11),
                        x: $util.fontSize(125),
                        y: 0
                    }
                }
            ]
        });
        return {
            gap: 25,
            style: {
                fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                    { offset: 0, color: $util.getNewColorWithTransparency(item.color,0.8,'rgba') },
                    { offset: 0.5, color: $util.getNewColorWithTransparency(item.color,0.8,'rgba')},
                    { offset: 0.5, color: item.color },     //柱状图从左向右颜色渐变
                    { offset: 1, color: item.color }
                ]),
                stroke: '#010C22',
                lineWidth: 4
            },
            ...item
        };
    });
    // 获取计算的数据
    let getData = getPyramidChart(resultData)
    let option: any = {
        backgroundColor: '',
        grid: {
            height: '176px' // 设置图表的最小高度为200像素
        },
        graphic: [
            {
                type: 'group',
                left: '3%',
                top: 'center',
                scale: [0.8, 0.8],
                onclick: function (params: any) {

                },
                children: getData
            },
            {
                type: 'group',
                left: '42%',
                top: 'center',
                scale: [1, 1],
                onclick: function (params: any) {

                },
                children: lengthData
            }
        ],
    }
    myChart.setOption(option)
}
// 数据处理
const getPyramidChart = (data: any) => {
    let domHeight = pyramidChartRef.value ? pyramidChartRef.value.clientHeight : 0;
    let domWidth = pyramidChartRef.value ? pyramidChartRef.value.clientWidth : 0;
    // 默认获取一个正方形空间
    let maxDistance = domHeight > domWidth / 2 ? domWidth / 2 : domHeight;
    // 合并设置
    let resultOption = Object.assign(
        {
            slanted: $util.fontSize(30 / data.length), // 每层底部的倾斜度
            maxWidth: maxDistance, // 金字塔最大宽度
            maxHeight: maxDistance, // 金字塔最大高度
            offset: 35 //偏差
        },
        {}
    );
    // 减去多余的误差边距
    resultOption.maxHeight = resultOption.maxHeight - resultOption.offset;
    // 一半最大宽度,用于计算左右边距
    let halfMaxWidth = resultOption.maxWidth / 2;
    // 数据最终
    let resultData: any = [];
    // 数据值 数组
    let dataNums = data.map((item: any) => item.rate || 0);
    // 计算数据总和
    let dataNumSum =
        dataNums.length > 0 &&
        dataNums.reduce(function (prev: any, curr: any) {
            return Number(prev || 0) + Number(curr || 0);
        });
    // 中间数据点坐标数组 根据长度比值算出
    let midlinePoint: any = [];
    let multipleLayer = [0.6];
    // 计算倍数等基础数据
    dataNums.forEach((item: any, index: number, arr: any) => {
        let itemNext = arr[index + 1];
        if (itemNext) {
            multipleLayer.push(itemNext / dataNums[0]); // 计算倍数
        }
        // 计算点坐标 长度
        let point: number =
            Math.round((item / dataNumSum) * resultOption.maxHeight * 1000) / 1000;
        midlinePoint.push(point);
    });
    // 三角形的高度
    let triangleHeight = 0;
    let triangleHeightLayer: any = [];
    // 三角形tan角度
    let triangleRatio = halfMaxWidth / resultOption.maxHeight;
    midlinePoint.forEach((item: any) => {
        triangleHeight = triangleHeight + item;
        triangleHeightLayer.push(triangleHeight);
    });
    // 中间数据点 最后的数据长度
    let midlinePointFinally =
        triangleHeightLayer[triangleHeightLayer.length - 1] || 0;
    // 开始拼接数据
    data.forEach((item: any, index: number) => {
        let arrObj: any = [];
        let triangleHeightLayerOne = triangleHeightLayer[index];
        let triangleHeightLayerOneLast = triangleHeightLayer[index - 1] || 0;
        let multipleLayerOne = multipleLayer[index];
        let multipleLayerOneLast = multipleLayer[index - 1] || 0;
        // 第一层数据单独处理
        if (index === 0) {
            arrObj.push(
                [0, 0],
                [
                    -triangleRatio *
                    (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
                    triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
                ],
                [0, triangleHeightLayerOne],
                [
                    triangleRatio *
                    (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
                    triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
                ]
            );
        } else {
            arrObj.push(
                [0, triangleHeightLayerOneLast],
                [
                    -triangleRatio *
                    (triangleHeightLayerOneLast -
                        resultOption.slanted * multipleLayerOneLast),
                    triangleHeightLayerOneLast -
                    resultOption.slanted * multipleLayerOneLast
                ],
                [
                    -triangleRatio *
                    (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
                    triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
                ],
                [0, triangleHeightLayerOne],
                [
                    triangleRatio *
                    (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
                    triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
                ],
                [
                    triangleRatio *
                    (triangleHeightLayerOneLast -
                        resultOption.slanted * multipleLayerOneLast),
                    triangleHeightLayerOneLast -
                    resultOption.slanted * multipleLayerOneLast
                ]
            );
        }
        resultData.push({
            type: 'polygon',
            z: 1,
            shape: {
                points: arrObj
            },
            name: item.name,
            style: item.style,
            polygonWidth: 57,
        })
    })
    // 添加线
    resultData.push({
        type: 'polyline',
        shape: {
            points: [
                [0, 0],
                [0, midlinePointFinally]
            ]
        },
        style: {
            stroke: '#f2f2f2',
            opacity: 0.2,
            lineWidth: 0
        },
        z: 2
    });
    // 返回
    return resultData;
}
//重新加载图表
const reloadChart = () => {
    disposeChart()
    getCharts()
}
const disposeChart = () => {
    if (myChart) {
        myChart.dispose();
    }
}
watch(
    () => props.chartData,
    (newValue, oldValue) => {
        let arr: any = []
        props.chartData.forEach((item: any, index: number) => {
            if (item.id) {
                arr.push({
                    name: item.label,
                    value: Number(item.value),
                    rate: props.chartData.length + 3 - index,
                    color: item.color,
                })
            }
        })
        data = arr.length > 0 ? sortedList(arr) : []
        reloadChart()
    },
    { deep: true, immediate: true, }
)
// 按照value顺序大小从小到大排列 并算出相应的赞比
const sortedList = (item: any) => {
    const total = item.reduce((sum: any, item: any) => sum + item.value, 0);
    return item.map((item: any) => {
        const percentage = (item.value / total) * 100;
        return { ...item, percentage: percentage.toFixed(2) }; // 保留两位小数
    }).sort((a: any, b: any) => Number(a.value) - Number(b.value)) // 升序排序
}
onMounted(async () => {
    window.addEventListener("resize", () => {
         setTimeout(() => {
            reloadChart()
            myChart.resize();
        }, 200)
    });
})
</script>
<style lang="scss" scoped>
.PyramidChart {

    #container {
        width: 100%;
        min-height: 176px;
        // height: 100%;

        div {
            width: 100%;
            height: 100%;
        }
    }
}
</style>
